home *** CD-ROM | disk | FTP | other *** search
- //-----------------------------------------------------------------------------
- // File: Cull.cpp
- //
- // Desc: Shows a technique for culling objects whose bounding boxes are
- // outside the view frustum. This technique is described at:
- // http://www.cs.unc.edu/~hoff/research/vfculler/viewcull.html
- //
- // Note: This code uses the D3D Framework helper library.
- //
- // Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved.
- //-----------------------------------------------------------------------------
- #define STRICT
- #include <math.h>
- #include <D3DX8.h>
- #include "D3DApp.h"
- #include "D3DFont.h"
- #include "D3DUtil.h"
- #include "DXUtil.h"
-
-
- //-----------------------------------------------------------------------------
- // Name: enum CULLSTATE
- // Desc: Represents the result of the culling calculation on an object.
- //-----------------------------------------------------------------------------
- enum CULLSTATE
- {
- CS_UNKNOWN, // cull state not yet computed
- CS_INSIDE, // object bounding box is at least partly inside the frustum
- CS_OUTSIDE, // object bounding box is outside the frustum
- CS_INSIDE_SLOW, // OBB is inside frustum, but it took extensive testing to determine this
- CS_OUTSIDE_SLOW, // OBB is outside frustum, but it took extensive testing to determine this
- };
-
-
- //-----------------------------------------------------------------------------
- // Name: struct CULLINFO
- // Desc: Stores information that will be used when culling objects. It needs
- // to be recomputed whenever the view matrix or projection matrix changes.
- //-----------------------------------------------------------------------------
- struct CULLINFO
- {
- D3DXVECTOR3 vecFrustum[8]; // corners of the view frustum
- D3DXPLANE planeFrustum[6]; // planes of the view frustum
- };
-
-
- // Prototypes for the culling functions
- VOID UpdateCullInfo( CULLINFO* pCullInfo, D3DXMATRIX* pMatView, D3DXMATRIX* pMatProj );
- CULLSTATE CullObject( CULLINFO* pCullInfo, D3DXVECTOR3* pVecBounds, D3DXPLANE* pPlaneBounds );
- BOOL EdgeIntersectsFace( D3DXVECTOR3* pEdges, D3DXVECTOR3* pFaces, D3DXPLANE* pPlane );
-
-
- //-----------------------------------------------------------------------------
- // Name: struct PLANEVERTEX
- // Desc: Custom vertex type used for drawing the frustum planes
- //-----------------------------------------------------------------------------
- struct PLANEVERTEX
- {
- D3DXVECTOR3 p;
- DWORD color;
- };
-
- #define D3DFVF_PLANEVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
-
-
- //-----------------------------------------------------------------------------
- // Name: class CCullableThing
- // Desc: A cullable object
- //-----------------------------------------------------------------------------
- class CCullableThing
- {
- public:
- D3DXVECTOR3 m_pos; // origin of object
- FLOAT m_fRotX; // rotation of object around X axis
- FLOAT m_fRotY; // rotation of object around Y axis
- D3DXMATRIX m_mat; // object's local-to-world transformation
- D3DXVECTOR3 m_vecBoundsLocal[8]; // bounding box coordinates (in local coord space)
- D3DXVECTOR3 m_vecBoundsWorld[8]; // bounding box coordinates (in world coord space)
- D3DXPLANE m_planeBoundsWorld[6]; // bounding box planes (in world coord space)
- CULLSTATE m_cullstate; // whether object is in the view frustum
-
- public:
- VOID Init(VOID)
- {
- // Pick a random position and orientation
- m_pos = D3DXVECTOR3( (FLOAT)(rand() % 50 - 25), // X is in (-25.0, 25.0)
- (FLOAT)(rand() % 50 - 25), // Y is in (-25.0, 25.0)
- (FLOAT)(rand() % 25) ); // Z is in ( 0.0, 25.0)
- m_fRotX = D3DXToRadian(rand() % 360);
- m_fRotY = D3DXToRadian(rand() % 360);
- UpdateMatrix();
- m_cullstate = CS_UNKNOWN;
- }
- VOID UpdateMatrix(VOID)
- {
- // Recompute m_mat, m_vecBoundsWorld, and m_planeBoundsWorld
- // when the thing's position, orientation, or bounding box has changed
- D3DXMATRIX matRotX, matRotY, matTrans;
- D3DXMatrixRotationX( &matRotX, m_fRotX );
- D3DXMatrixRotationY( &matRotY, m_fRotY );
- D3DXMatrixTranslation( &matTrans, m_pos.x, m_pos.y, m_pos.z );
- m_mat = matRotX * matRotY * matTrans;
-
- // Transform bounding box coords from local space to world space
- for( int i = 0; i < 8; i++ )
- D3DXVec3TransformCoord( &m_vecBoundsWorld[i], &m_vecBoundsLocal[i], &m_mat );
-
- // Determine planes of the bounding box
- D3DXPlaneFromPoints( &m_planeBoundsWorld[0], &m_vecBoundsWorld[0],
- &m_vecBoundsWorld[1], &m_vecBoundsWorld[2] ); // Near
- D3DXPlaneFromPoints( &m_planeBoundsWorld[1], &m_vecBoundsWorld[6],
- &m_vecBoundsWorld[7], &m_vecBoundsWorld[5] ); // Far
- D3DXPlaneFromPoints( &m_planeBoundsWorld[2], &m_vecBoundsWorld[2],
- &m_vecBoundsWorld[6], &m_vecBoundsWorld[4] ); // Left
- D3DXPlaneFromPoints( &m_planeBoundsWorld[3], &m_vecBoundsWorld[7],
- &m_vecBoundsWorld[3], &m_vecBoundsWorld[5] ); // Right
- D3DXPlaneFromPoints( &m_planeBoundsWorld[4], &m_vecBoundsWorld[2],
- &m_vecBoundsWorld[3], &m_vecBoundsWorld[6] ); // Top
- D3DXPlaneFromPoints( &m_planeBoundsWorld[5], &m_vecBoundsWorld[1],
- &m_vecBoundsWorld[0], &m_vecBoundsWorld[4] ); // Bottom
- }
- };
-
-
- //-----------------------------------------------------------------------------
- // Name: struct Camera
- // Desc:
- //-----------------------------------------------------------------------------
- struct Camera
- {
- D3DXVECTOR3 m_vPosition;
- D3DXVECTOR3 m_vVelocity;
- FLOAT m_fYaw;
- FLOAT m_fYawVelocity;
- FLOAT m_fPitch;
- FLOAT m_fPitchVelocity;
- D3DXMATRIX m_matView;
- D3DXMATRIX m_matOrientation;
- };
-
-
- //-----------------------------------------------------------------------------
- // Name: class CMyD3DApplication
- // Desc: Application class. The base class (CD3DApplication) provides the
- // generic functionality needed in all Direct3D samples. CMyD3DApplication
- // adds functionality specific to this sample program.
- //-----------------------------------------------------------------------------
- class CMyD3DApplication : public CD3DApplication
- {
- CD3DFont* m_pFont; // Font for drawing text
- CD3DFont* m_pFontSmall;
-
- LPD3DXMESH m_pMeshTeapot; // Mesh of thing to be cull-tested
- LPD3DXMESH m_pMeshBox; // Mesh to visualize bounding box
- D3DXMATRIX m_matBox; // Matrix that places bounding box correctly on teapot
-
- LPDIRECT3DVERTEXBUFFER8 m_pPlaneVB[6]; // VBs to visualize the view frustum
-
- // The things to render and cull
- CCullableThing m_CullableThingArray[50];
- DWORD m_dwNumCullableThings;
-
- // Variables for determining the view
- BYTE m_bKey[256];
- BOOL m_bLeftActive; // left vs right view currently active
- Camera m_CameraLeft;
- Camera m_CameraRight;
- D3DXMATRIX m_matProjLeft;
- D3DXMATRIX m_matProjRight;
-
- D3DMATERIAL8 m_mtrlOutside;
- D3DMATERIAL8 m_mtrlInside;
- D3DMATERIAL8 m_mtrlOutsideSlow;
- D3DMATERIAL8 m_mtrlInsideSlow;
- D3DMATERIAL8 m_mtrlWhite;
-
- CULLINFO m_cullinfo;
- BOOL m_bShowHelp;
-
- protected:
- HRESULT OneTimeSceneInit();
- HRESULT InitDeviceObjects();
- HRESULT RestoreDeviceObjects();
- HRESULT InvalidateDeviceObjects();
- HRESULT DeleteDeviceObjects();
- HRESULT Render();
- HRESULT RenderScene( BOOL bRenderPlanes );
- HRESULT FrameMove();
- HRESULT FinalCleanup();
- VOID UpdateCamera(Camera* pCamera);
- HRESULT UpdatePlaneVBs(VOID);
- VOID CullObjects(VOID);
-
- public:
- CMyD3DApplication();
- LRESULT MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
- };
-
-
-
-
-
- //-----------------------------------------------------------------------------
- // Name: WinMain()
- // Desc: Entry point to the program. Initializes everything, and goes into a
- // message-processing loop. Idle time is used to render the scene.
- //-----------------------------------------------------------------------------
- INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
- {
- CMyD3DApplication d3dApp;
-
- if( FAILED( d3dApp.Create( hInst ) ) )
- return 0;
-
- return d3dApp.Run();
- }
-
-
-
-
- //-----------------------------------------------------------------------------
- // Name: CMyD3DApplication()
- // Desc: Application constructor. Sets attributes for the app.
- //-----------------------------------------------------------------------------
- CMyD3DApplication::CMyD3DApplication()
- {
- m_strWindowTitle = _T("Cull: Culling nonvisible objects");
- m_bUseDepthBuffer = TRUE;
- m_dwCreationWidth = 600;
- m_dwCreationHeight = 300;
- m_bShowCursorWhenFullscreen = TRUE;
-
- m_pFont = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD );
- m_pFontSmall = new CD3DFont( _T("Arial"), 9, D3DFONT_BOLD );
- m_pMeshTeapot = NULL;
- m_pMeshBox = NULL;
- m_dwNumCullableThings = 0;
-
- ZeroMemory( m_pPlaneVB, sizeof(m_pPlaneVB) );
- ZeroMemory( m_bKey, 256 );
- ZeroMemory( &m_CameraLeft, sizeof(m_CameraLeft) );
- ZeroMemory( &m_CameraRight, sizeof(m_CameraRight) );
-
- m_bLeftActive = TRUE;
- m_bShowHelp = FALSE;
- }
-
-
-
-
- //-----------------------------------------------------------------------------
- // Name: OneTimeSceneInit()
- // Desc: Called during initial app startup, this function performs all the
- // permanent initialization.
- //-----------------------------------------------------------------------------
- HRESULT CMyD3DApplication::OneTimeSceneInit()
- {
- // Initialize cullable things
- for( int i = 0; i < 50; i++ )
- {
- m_CullableThingArray[m_dwNumCullableThings].Init();
- m_dwNumCullableThings++;
- }
-
- UpdateCamera( &m_CameraLeft );
- UpdateCamera( &m_CameraRight );
-
- return S_OK;
- }
-
-
-
-
- //-----------------------------------------------------------------------------
- // Name: FrameMove()
- // Desc: Called once per frame, the call is the entry point for animating
- // the scene.
- //-----------------------------------------------------------------------------
- HRESULT CMyD3DApplication::FrameMove()
- {
- BOOL bNeedToCull = FALSE;
-
- // Handle object rotations
- if( m_bKey['Y'] || m_bKey['U'] || m_bKey['H'] || m_bKey['J'])
- {
- CCullableThing* pCullableThing;
- for( DWORD iThing = 0; iThing < m_dwNumCullableThings; iThing++ )
- {
- pCullableThing = &m_CullableThingArray[iThing];
- if( m_bKey['Y'] )
- pCullableThing->m_fRotY += m_fElapsedTime;
- else if( m_bKey['U'] )
- pCullableThing->m_fRotY -= m_fElapsedTime;
- if( m_bKey['H'] )
- pCullableThing->m_fRotX += m_fElapsedTime;
- else if( m_bKey['J'] )
- pCullableThing->m_fRotX -= m_fElapsedTime;
- pCullableThing->UpdateMatrix();
- }
- bNeedToCull = TRUE;
- }
-
- // Handle camera motion
- UpdateCamera(m_bLeftActive ? &m_CameraLeft : &m_CameraRight);
- if( !m_bLeftActive )
- {
- UpdateCullInfo( &m_cullinfo, &m_CameraRight.m_matView, &m_matProjRight );
- bNeedToCull = TRUE;
- UpdatePlaneVBs();
- }
-
- // Re-determine cull state of all objects if necessary
- if( bNeedToCull )
- CullObjects();
-
- return S_OK;
- }
-
-
-
-
- //-----------------------------------------------------------------------------
- // Name: Render()
- // Desc: Called once per frame, the call is the entry point for 3d
- // rendering. This function sets up render states, clears the
- // viewport, and renders the scene.
- //-----------------------------------------------------------------------------
- HRESULT CMyD3DApplication::Render()
- {
- // The "hot" clear color is used to indicate the viewport
- // whose camera is currently being controlled by the keyboard
- const DWORD dwHotClearColor = 0xff0000ff;
- const DWORD dwColdClearColor = 0xff000080;
-
- //
- // Draw left viewport
- //
- D3DVIEWPORT8 vp;
- vp.X = 0;
- vp.Y = 0;
- vp.Width = m_d3dsdBackBuffer.Width / 2;
- vp.Height = m_d3dsdBackBuffer.Height;
- vp.MinZ = 0.0f;
- vp.MaxZ = 1.0f;
- m_pd3dDevice->SetViewport( &vp );
-
- m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
- m_bLeftActive ? dwHotClearColor : dwColdClearColor, 1.0f, 0L );
-
- m_pd3dDevice->SetTransform( D3DTS_VIEW, &m_CameraLeft.m_matView );
- m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &m_matProjLeft );
-
- // Draw contents of left viewport
- RenderScene( TRUE ); // TRUE means render frustum planes
-
- //
- // Draw right viewport
- //
- vp.X = m_d3dsdBackBuffer.Width / 2;
- vp.Width = m_d3dsdBackBuffer.Width / 2;
- m_pd3dDevice->SetViewport( &vp );
-
- m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
- m_bLeftActive ? dwColdClearColor : dwHotClearColor, 1.0f, 0L );
-
- m_pd3dDevice->SetTransform( D3DTS_VIEW, &m_CameraRight.m_matView );
- m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &m_matProjRight );
-
- // Draw contents of right viewport
- RenderScene( FALSE ); // FALSE means don't render frustum planes
-
- return S_OK;
- }
-
-
-
-
- //-----------------------------------------------------------------------------
- // Name: RenderScene()
- // Desc:
- //-----------------------------------------------------------------------------
- HRESULT CMyD3DApplication::RenderScene( BOOL bRenderPlanes )
- {
- // Begin the scene
- if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
- {
- // Render each object
- CCullableThing* pCullableThing;
- for( DWORD iThing = 0; iThing < m_dwNumCullableThings; iThing++ )
- {
- pCullableThing = &m_CullableThingArray[iThing];
-
- // Normally, if the cullstate is CS_OUTSIDE or CS_OUTSIDE_SLOW,
- // there is no need to ask D3D to render the object since
- // it's outside the view frustum. Since this app is meant to
- // visualize the culling process, all objects are passed to D3D,
- // and different colors are used to show their cullstates.
-
- switch( pCullableThing->m_cullstate )
- {
- case CS_UNKNOWN:
- m_pd3dDevice->SetMaterial( &m_mtrlWhite );
- break;
- case CS_OUTSIDE:
- m_pd3dDevice->SetMaterial( &m_mtrlOutside );
- break;
- case CS_INSIDE:
- m_pd3dDevice->SetMaterial( &m_mtrlInside );
- break;
- case CS_OUTSIDE_SLOW:
- m_pd3dDevice->SetMaterial( &m_mtrlOutsideSlow );
- break;
- case CS_INSIDE_SLOW:
- m_pd3dDevice->SetMaterial( &m_mtrlInsideSlow );
- break;
- }
- m_pd3dDevice->SetTransform( D3DTS_WORLD, &pCullableThing->m_mat );
- m_pMeshTeapot->DrawSubset( 0 );
- D3DXMATRIX mat = m_matBox * pCullableThing->m_mat;
- m_pd3dDevice->SetTransform( D3DTS_WORLD, &mat );
- m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
- m_pMeshBox->DrawSubset( 0 );
- m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
- }
-
- if( bRenderPlanes )
- {
- // Render frustum planes
- m_pd3dDevice->SetMaterial( &m_mtrlWhite );
- D3DXMATRIX mat;
- D3DXMatrixIdentity( &mat );
- m_pd3dDevice->SetTransform( D3DTS_WORLD, &mat );
- m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
- m_pd3dDevice->SetVertexShader( D3DFVF_PLANEVERTEX );
- m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
- for( int iPlane = 0; iPlane < 6; iPlane++ )
- {
- m_pd3dDevice->SetStreamSource( 0, m_pPlaneVB[iPlane], sizeof(PLANEVERTEX) );
- m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
- }
- m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
- m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
- }
-
- // Output statistics
- m_pFont->DrawText( 2, 0, D3DCOLOR_ARGB(255,255,255,0), m_strFrameStats );
- m_pFont->DrawText( 2, 20, D3DCOLOR_ARGB(255,255,255,0), m_strDeviceStats );
-
- // Show help
- if( m_bShowHelp )
- {
- m_pFontSmall->DrawText( 2, 40, D3DCOLOR_ARGB(255,200,100,100),
- _T("Press F1 to hide help\n")
- _T("The right viewport is the frustum being culled against.\n")
- _T("The left viewport has its own camera that lets you view\n")
- _T("the scene and frustum from different angles.\n")
- _T("Click the viewport whose camera you want to control.\n")
- _T("Keyboard controls:") );
- m_pFontSmall->DrawText( 20, 140, D3DCOLOR_ARGB(255,200,100,100),
- _T("Move\n")
- _T("Turn\n")
- _T("Spin objects\n")
- _T("Snap left view to viewport\n")
- _T("Snap right view to origin\n") );
- m_pFontSmall->DrawText( 210, 140, D3DCOLOR_ARGB(255,200,100,100),
- _T("W, S, Arrow keys\n")
- _T("Q, E, A, Z\n")
- _T("Y, U, H, J\n")
- _T("N\n")
- _T("M") );
- }
- else
- {
- m_pFontSmall->DrawText( 2, 40, D3DCOLOR_ARGB(255,200,100,100),
- _T("Press F1 for help") );
- }
-
- // End the scene.
- m_pd3dDevice->EndScene();
- }
-
- return S_OK;
- }
-
-
-
-
- //-----------------------------------------------------------------------------
- // Name: UpdateCamera()
- // Desc:
- //-----------------------------------------------------------------------------
- VOID CMyD3DApplication::UpdateCamera(Camera* pCamera)
- {
- FLOAT fElapsedTime;
-
- if( m_fElapsedTime > 0.0f )
- fElapsedTime = m_fElapsedTime;
- else
- fElapsedTime = 0.05f;
-
- FLOAT fSpeed = 5.0f*fElapsedTime;
- FLOAT fAngularSpeed = 2.0f*fElapsedTime;
-
- // De-accelerate the camera movement (for smooth motion)
- pCamera->m_vVelocity *= 0.75f;
- pCamera->m_fYawVelocity *= 0.75f;
- pCamera->m_fPitchVelocity *= 0.75f;
-
- // Process keyboard input
- if( m_bKey[VK_RIGHT] ) pCamera->m_vVelocity.x += fSpeed; // Slide Right
- if( m_bKey[VK_LEFT] ) pCamera->m_vVelocity.x -= fSpeed; // Slide Left
- if( m_bKey[VK_UP] ) pCamera->m_vVelocity.y += fSpeed; // Slide Up
- if( m_bKey[VK_DOWN] ) pCamera->m_vVelocity.y -= fSpeed; // Slide Down
- if( m_bKey['W'] ) pCamera->m_vVelocity.z += fSpeed; // Move Forward
- if( m_bKey['S'] ) pCamera->m_vVelocity.z -= fSpeed; // Move Backward
- if( m_bKey['E'] ) pCamera->m_fYawVelocity += fSpeed; // Turn Right
- if( m_bKey['Q'] ) pCamera->m_fYawVelocity -= fSpeed; // Turn Left
- if( m_bKey['Z'] ) pCamera->m_fPitchVelocity += fSpeed; // Turn Down
- if( m_bKey['A'] ) pCamera->m_fPitchVelocity -= fSpeed; // Turn Up
-
- // Update the position vector
- D3DXVECTOR3 vT = pCamera->m_vVelocity * fSpeed;
- D3DXVec3TransformNormal( &vT, &vT, &pCamera->m_matOrientation );
- pCamera->m_vPosition += vT;
-
- // Update the yaw-pitch-rotation vector
- pCamera->m_fYaw += fAngularSpeed * pCamera->m_fYawVelocity;
- pCamera->m_fPitch += fAngularSpeed * pCamera->m_fPitchVelocity;
- if( pCamera->m_fPitch < -D3DX_PI/2 )
- pCamera->m_fPitch = -D3DX_PI/2;
- if( pCamera->m_fPitch > D3DX_PI/2 )
- pCamera->m_fPitch = D3DX_PI/2;
-
- // Set the view matrix
- D3DXQUATERNION qR;
- D3DXQuaternionRotationYawPitchRoll( &qR, pCamera->m_fYaw, pCamera->m_fPitch, 0.0f );
- D3DXMatrixAffineTransformation( &pCamera->m_matOrientation, 1.25f, NULL, &qR, &pCamera->m_vPosition );
- D3DXMatrixInverse( &pCamera->m_matView, NULL, &pCamera->m_matOrientation );
- }
-
-
-
-
- //-----------------------------------------------------------------------------
- // Name: UpdatePlaneVBs()
- // Desc: Update the vertex buffers to match the view frustum. Slightly
- // different colors are used for each plane to make them easier to
- // distinguish from each other.
- //-----------------------------------------------------------------------------
- HRESULT CMyD3DApplication::UpdatePlaneVBs()
- {
- HRESULT hr;
- for( int iPlane = 0; iPlane < 6; iPlane++ )
- {
- PLANEVERTEX* v;
- if( FAILED(hr = m_pPlaneVB[iPlane]->Lock( 0, 0, (BYTE**)&v, 0 ) ) )
- return hr;
- switch( iPlane )
- {
- case 0: // near
- v[0].p = m_cullinfo.vecFrustum[0];
- v[1].p = m_cullinfo.vecFrustum[1];
- v[2].p = m_cullinfo.vecFrustum[2];
- v[3].p = m_cullinfo.vecFrustum[3];
- v[0].color = v[1].color = v[2].color = v[3].color = 0x80505050;
- break;
- case 1: // far
- v[0].p = m_cullinfo.vecFrustum[4];
- v[1].p = m_cullinfo.vecFrustum[6];
- v[2].p = m_cullinfo.vecFrustum[5];
- v[3].p = m_cullinfo.vecFrustum[7];
- v[0].color = v[1].color = v[2].color = v[3].color = 0x80404040;
- break;
- case 2: // left
- v[0].p = m_cullinfo.vecFrustum[0];
- v[1].p = m_cullinfo.vecFrustum[2];
- v[2].p = m_cullinfo.vecFrustum[4];
- v[3].p = m_cullinfo.vecFrustum[6];
- v[0].color = v[1].color = v[2].color = v[3].color = 0x80404040;
- break;
- case 3:
- v[0].p = m_cullinfo.vecFrustum[1];
- v[1].p = m_cullinfo.vecFrustum[3];
- v[2].p = m_cullinfo.vecFrustum[5];
- v[3].p = m_cullinfo.vecFrustum[7];
- v[0].color = v[1].color = v[2].color = v[3].color = 0x80606060;
- break;
- case 4:
- v[0].p = m_cullinfo.vecFrustum[2];
- v[1].p = m_cullinfo.vecFrustum[3];
- v[2].p = m_cullinfo.vecFrustum[6];
- v[3].p = m_cullinfo.vecFrustum[7];
- v[0].color = v[1].color = v[2].color = v[3].color = 0x80505050;
- break;
- case 5:
- v[0].p = m_cullinfo.vecFrustum[0];
- v[1].p = m_cullinfo.vecFrustum[1];
- v[2].p = m_cullinfo.vecFrustum[4];
- v[3].p = m_cullinfo.vecFrustum[5];
- v[0].color = v[1].color = v[2].color = v[3].color = 0x80505050;
- break;
- }
- m_pPlaneVB[iPlane]->Unlock();
- }
-
- return S_OK;
- }
-
-
-
- //-----------------------------------------------------------------------------
- // Name: InitDeviceObjects()
- // Desc: Initialize scene objects.
- //-----------------------------------------------------------------------------
- HRESULT CMyD3DApplication::InitDeviceObjects()
- {
- HRESULT hr;
-
- // Initialize the font's internal textures
- if( FAILED( hr = m_pFont->InitDeviceObjects( m_pd3dDevice ) ) )
- return hr;
- if( FAILED( hr = m_pFontSmall->InitDeviceObjects( m_pd3dDevice ) ) )
- return hr;
-
- // Create a teapot mesh
- if( FAILED( D3DXCreateTeapot( m_pd3dDevice, &m_pMeshTeapot, NULL ) ) )
- return hr;
- D3DXComputeNormals( m_pMeshTeapot, NULL );
-
- // Determine bounding box of the teapot
- D3DXVECTOR3 vecMin;
- D3DXVECTOR3 vecMax;
- BYTE* pVertices;
- if( FAILED( hr = m_pMeshTeapot->LockVertexBuffer(D3DLOCK_READONLY, &pVertices) ) )
- return hr;
- hr = D3DXComputeBoundingBox( pVertices, m_pMeshTeapot->GetNumVertices(),
- m_pMeshTeapot->GetFVF(), &vecMin, &vecMax );
- m_pMeshTeapot->UnlockVertexBuffer();
-
- // Note that the m_vecBoundsLocal are identical for every CullableThing
- // because the cullable things are all the same teapot object. In a real
- // app, of course, they would all be potentially different.
- CCullableThing* pCullableThing;
- for( DWORD iThing = 0; iThing < m_dwNumCullableThings; iThing++ )
- {
- pCullableThing = &m_CullableThingArray[iThing];
- pCullableThing->m_vecBoundsLocal[0] = D3DXVECTOR3( vecMin.x, vecMin.y, vecMin.z ); // xyz
- pCullableThing->m_vecBoundsLocal[1] = D3DXVECTOR3( vecMax.x, vecMin.y, vecMin.z ); // Xyz
- pCullableThing->m_vecBoundsLocal[2] = D3DXVECTOR3( vecMin.x, vecMax.y, vecMin.z ); // xYz
- pCullableThing->m_vecBoundsLocal[3] = D3DXVECTOR3( vecMax.x, vecMax.y, vecMin.z ); // XYz
- pCullableThing->m_vecBoundsLocal[4] = D3DXVECTOR3( vecMin.x, vecMin.y, vecMax.z ); // xyZ
- pCullableThing->m_vecBoundsLocal[5] = D3DXVECTOR3( vecMax.x, vecMin.y, vecMax.z ); // XyZ
- pCullableThing->m_vecBoundsLocal[6] = D3DXVECTOR3( vecMin.x, vecMax.y, vecMax.z ); // xYZ
- pCullableThing->m_vecBoundsLocal[7] = D3DXVECTOR3( vecMax.x, vecMax.y, vecMax.z ); // XYZ
- pCullableThing->UpdateMatrix();
- }
-
- // Set up m_matBox to be able to render the bounding box properly
- D3DXMATRIX matTrans;
- D3DXMATRIX matScale;
- D3DXMatrixTranslation( &matTrans, (vecMin.x + vecMax.x) / 2,
- (vecMin.y + vecMax.y) / 2, (vecMin.z + vecMax.z) / 2 );
- D3DXMatrixScaling( &matScale, vecMax.x - vecMin.x, vecMax.y - vecMin.y, vecMax.z - vecMin.z );
- m_matBox = matScale * matTrans;
-
- if( FAILED( hr = D3DXCreateBox( m_pd3dDevice, 1.0f, 1.0f, 1.0f, &m_pMeshBox, NULL ) ) )
- return hr;
- D3DXComputeNormals( m_pMeshBox, NULL );
-
- // Create VBs for frustum planes
- for( int iPlane = 0; iPlane < 6; iPlane++ )
- {
- if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( 4*sizeof(PLANEVERTEX),
- D3DUSAGE_WRITEONLY, D3DFVF_PLANEVERTEX, D3DPOOL_MANAGED, &m_pPlaneVB[iPlane] ) ) )
- {
- return hr;
- }
- }
-
- return S_OK;
- }
-
-
-
-
- //-----------------------------------------------------------------------------
- // Name: RestoreDeviceObjects()
- // Desc: Initialize scene objects.
- //-----------------------------------------------------------------------------
- HRESULT CMyD3DApplication::RestoreDeviceObjects()
- {
- m_pFont->RestoreDeviceObjects();
- m_pFontSmall->RestoreDeviceObjects();
-
- // Set miscellaneous render states
- m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE, TRUE );
- m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
-
- m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
- m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
-
- // Set up the matrices
- FLOAT fAspect = m_d3dsdBackBuffer.Width / (FLOAT)m_d3dsdBackBuffer.Height;
- D3DXMatrixPerspectiveFovLH( &m_matProjRight, D3DX_PI/4, fAspect, 0.2f, 10.0f );
- D3DXMatrixPerspectiveFovLH( &m_matProjLeft, D3DX_PI/4, fAspect, 0.2f, 200.0f );
-
- // Set up a light
- if( ( m_d3dCaps.VertexProcessingCaps & D3DVTXPCAPS_DIRECTIONALLIGHTS ) ||
- !( m_dwCreateFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING ) )
- {
- D3DLIGHT8 light;
- D3DUtil_InitLight( light, D3DLIGHT_DIRECTIONAL, 0.2f, -0.4f, 0.2f );
- m_pd3dDevice->SetLight( 0, &light );
- m_pd3dDevice->LightEnable( 0, TRUE );
- }
- m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xff555555 );
-
- // Set up materials
- D3DUtil_InitMaterial(m_mtrlInside, 0.2f, 0.6f, 0.2f, 0.5f); // dark green
- D3DUtil_InitMaterial(m_mtrlOutside, 0.6f, 0.2f, 0.2f, 0.5f); // dark red
- D3DUtil_InitMaterial(m_mtrlInsideSlow, 0.7f, 1.0f, 0.7f, 0.5f); // pastel green
- D3DUtil_InitMaterial(m_mtrlOutsideSlow, 1.0f, 0.7f, 0.7f, 0.5f); // pastel red
- D3DUtil_InitMaterial(m_mtrlWhite, 1.0f, 1.0f, 1.0f, 0.5f); // white
-
- UpdateCullInfo( &m_cullinfo, &m_CameraRight.m_matView, &m_matProjRight );
- CullObjects();
- UpdatePlaneVBs();
-
- return S_OK;
- }
-
-
-
-
- //-----------------------------------------------------------------------------
- // Name: InvalidateDeviceObjects()
- // Desc:
- //-----------------------------------------------------------------------------
- HRESULT CMyD3DApplication::InvalidateDeviceObjects()
- {
- m_pFont->InvalidateDeviceObjects();
- m_pFontSmall->InvalidateDeviceObjects();
-
- return S_OK;
- }
-
-
-
-
- //-----------------------------------------------------------------------------
- // Name: DeleteDeviceObjects()
- // Desc: Called when the app is exiting, or the device is being changed,
- // this function deletes any device dependent objects.
- //-----------------------------------------------------------------------------
- HRESULT CMyD3DApplication::DeleteDeviceObjects()
- {
- m_pFont->DeleteDeviceObjects();
- m_pFontSmall->DeleteDeviceObjects();
- SAFE_RELEASE( m_pMeshTeapot );
- SAFE_RELEASE( m_pMeshBox );
-
- for( int iPlane = 0; iPlane < 6; iPlane++ )
- SAFE_RELEASE( m_pPlaneVB[iPlane] );
-
- return S_OK;
- }
-
-
-
-
- //-----------------------------------------------------------------------------
- // Name: FinalCleanup()
- // Desc: Called before the app exits, this function gives the app the chance
- // to cleanup after itself.
- //-----------------------------------------------------------------------------
- HRESULT CMyD3DApplication::FinalCleanup()
- {
- SAFE_DELETE( m_pFont );
- SAFE_DELETE( m_pFontSmall );
-
- return S_OK;
- }
-
-
-
-
- //-----------------------------------------------------------------------------
- // Name: MsgProc()
- // Desc: Message proc function to handle key and menu input
- //-----------------------------------------------------------------------------
- LRESULT CMyD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
- LPARAM lParam )
- {
- // Record key presses
- if( WM_KEYDOWN == uMsg )
- {
- m_bKey[wParam] = 1;
- }
- // Perform commands when keys are released
- if( WM_KEYUP == uMsg )
- {
- m_bKey[wParam] = 0;
- switch( wParam )
- {
- case 'N': // Set left camera to match right camera
- m_CameraLeft = m_CameraRight;
- break;
- case 'M': // Reset right camera to original orientation
- ZeroMemory( &m_CameraRight, sizeof(m_CameraRight) );
- UpdateCamera( &m_CameraRight );
- UpdateCullInfo( &m_cullinfo, &m_CameraRight.m_matView, &m_matProjRight );
- CullObjects();
- UpdatePlaneVBs();
- break;
- case VK_F1:
- m_bShowHelp = !m_bShowHelp;
- break;
- }
- }
- if( WM_LBUTTONDOWN == uMsg )
- {
- INT x = LOWORD(lParam);
- if( x < (INT)m_d3dsdBackBuffer.Width / 2 )
- m_bLeftActive = TRUE;
- else
- m_bLeftActive = FALSE;
- }
-
- return CD3DApplication::MsgProc( hWnd, uMsg, wParam, lParam );
- }
-
-
-
-
- //-----------------------------------------------------------------------------
- // Name: CullObjects()
- // Desc: Cull each object in the CCullableThing array
- //-----------------------------------------------------------------------------
- VOID CMyD3DApplication::CullObjects(VOID)
- {
- CCullableThing* pCullableThing;
-
- for( DWORD iThing = 0; iThing < m_dwNumCullableThings; iThing++ )
- {
- pCullableThing = &m_CullableThingArray[iThing];
- pCullableThing->m_cullstate = CullObject( &m_cullinfo,
- pCullableThing->m_vecBoundsWorld, pCullableThing->m_planeBoundsWorld );
- }
- }
-
-
-
-
- //-----------------------------------------------------------------------------
- // Name: UpdateCullInfo()
- // Desc: Sets up the frustum planes, endpoints, and center for the frustum
- // defined by a given view matrix and projection matrix. This info will
- // be used when culling each object in CullObject().
- //-----------------------------------------------------------------------------
- VOID UpdateCullInfo( CULLINFO* pCullInfo, D3DXMATRIX* pMatView, D3DXMATRIX* pMatProj )
- {
- D3DXMATRIX mat;
-
- D3DXMatrixMultiply( &mat, pMatView, pMatProj );
- D3DXMatrixInverse( &mat, NULL, &mat );
-
- pCullInfo->vecFrustum[0] = D3DXVECTOR3(-1.0f, -1.0f, 0.0f); // xyz
- pCullInfo->vecFrustum[1] = D3DXVECTOR3( 1.0f, -1.0f, 0.0f); // Xyz
- pCullInfo->vecFrustum[2] = D3DXVECTOR3(-1.0f, 1.0f, 0.0f); // xYz
- pCullInfo->vecFrustum[3] = D3DXVECTOR3( 1.0f, 1.0f, 0.0f); // XYz
- pCullInfo->vecFrustum[4] = D3DXVECTOR3(-1.0f, -1.0f, 1.0f); // xyZ
- pCullInfo->vecFrustum[5] = D3DXVECTOR3( 1.0f, -1.0f, 1.0f); // XyZ
- pCullInfo->vecFrustum[6] = D3DXVECTOR3(-1.0f, 1.0f, 1.0f); // xYZ
- pCullInfo->vecFrustum[7] = D3DXVECTOR3( 1.0f, 1.0f, 1.0f); // XYZ
-
- for( INT i = 0; i < 8; i++ )
- D3DXVec3TransformCoord( &pCullInfo->vecFrustum[i], &pCullInfo->vecFrustum[i], &mat );
-
- D3DXPlaneFromPoints( &pCullInfo->planeFrustum[0], &pCullInfo->vecFrustum[0],
- &pCullInfo->vecFrustum[1], &pCullInfo->vecFrustum[2] ); // Near
- D3DXPlaneFromPoints( &pCullInfo->planeFrustum[1], &pCullInfo->vecFrustum[6],
- &pCullInfo->vecFrustum[7], &pCullInfo->vecFrustum[5] ); // Far
- D3DXPlaneFromPoints( &pCullInfo->planeFrustum[2], &pCullInfo->vecFrustum[2],
- &pCullInfo->vecFrustum[6], &pCullInfo->vecFrustum[4] ); // Left
- D3DXPlaneFromPoints( &pCullInfo->planeFrustum[3], &pCullInfo->vecFrustum[7],
- &pCullInfo->vecFrustum[3], &pCullInfo->vecFrustum[5] ); // Right
- D3DXPlaneFromPoints( &pCullInfo->planeFrustum[4], &pCullInfo->vecFrustum[2],
- &pCullInfo->vecFrustum[3], &pCullInfo->vecFrustum[6] ); // Top
- D3DXPlaneFromPoints( &pCullInfo->planeFrustum[5], &pCullInfo->vecFrustum[1],
- &pCullInfo->vecFrustum[0], &pCullInfo->vecFrustum[4] ); // Bottom
- }
-
-
-
-
- //-----------------------------------------------------------------------------
- // Name: CullObject()
- // Desc: Determine the cullstate for an object bounding box (OBB).
- // The algorithm is:
- // 1) If any OBB corner pt is inside the frustum, return CS_INSIDE
- // 2) Else if all OBB corner pts are outside a single frustum plane,
- // return CS_OUTSIDE
- // 3) Else if any frustum edge penetrates a face of the OBB, return
- // CS_INSIDE_SLOW
- // 4) Else if any OBB edge penetrates a face of the frustum, return
- // CS_INSIDE_SLOW
- // 5) Else if any point in the frustum is outside any plane of the
- // OBB, return CS_OUTSIDE_SLOW
- // 6) Else return CS_INSIDE_SLOW
- //-----------------------------------------------------------------------------
- CULLSTATE CullObject( CULLINFO* pCullInfo, D3DXVECTOR3* pVecBounds,
- D3DXPLANE* pPlaneBounds )
- {
- BYTE bOutside[8];
- ZeroMemory( &bOutside, sizeof(bOutside) );
-
- // Check boundary vertices against all 6 frustum planes,
- // and store result (1 if outside) in a bitfield
- for( int iPoint = 0; iPoint < 8; iPoint++ )
- {
- for( int iPlane = 0; iPlane < 6; iPlane++ )
- {
- if( pCullInfo->planeFrustum[iPlane].a * pVecBounds[iPoint].x +
- pCullInfo->planeFrustum[iPlane].b * pVecBounds[iPoint].y +
- pCullInfo->planeFrustum[iPlane].c * pVecBounds[iPoint].z +
- pCullInfo->planeFrustum[iPlane].d < 0)
- {
- bOutside[iPoint] |= (1 << iPlane);
- }
- }
- // If any point is inside all 6 frustum planes, it is inside
- // the frustum, so the object must be rendered.
- if( bOutside[iPoint] == 0 )
- return CS_INSIDE;
- }
-
- // If all points are outside any single frustum plane, the object is
- // outside the frustum
- if( (bOutside[0] & bOutside[1] & bOutside[2] & bOutside[3] &
- bOutside[4] & bOutside[5] & bOutside[6] & bOutside[7]) != 0 )
- {
- return CS_OUTSIDE;
- }
-
- // Now see if any of the frustum edges penetrate any of the faces of
- // the bounding box
- D3DXVECTOR3 edge[12][2] =
- {
- pCullInfo->vecFrustum[0], pCullInfo->vecFrustum[1], // front bottom
- pCullInfo->vecFrustum[2], pCullInfo->vecFrustum[3], // front top
- pCullInfo->vecFrustum[0], pCullInfo->vecFrustum[2], // front left
- pCullInfo->vecFrustum[1], pCullInfo->vecFrustum[3], // front right
- pCullInfo->vecFrustum[4], pCullInfo->vecFrustum[5], // back bottom
- pCullInfo->vecFrustum[6], pCullInfo->vecFrustum[7], // back top
- pCullInfo->vecFrustum[4], pCullInfo->vecFrustum[6], // back left
- pCullInfo->vecFrustum[5], pCullInfo->vecFrustum[7], // back right
- pCullInfo->vecFrustum[0], pCullInfo->vecFrustum[4], // left bottom
- pCullInfo->vecFrustum[2], pCullInfo->vecFrustum[6], // left top
- pCullInfo->vecFrustum[1], pCullInfo->vecFrustum[5], // right bottom
- pCullInfo->vecFrustum[3], pCullInfo->vecFrustum[7], // right top
- };
- D3DXVECTOR3 face[6][4] =
- {
- pVecBounds[0], pVecBounds[2], pVecBounds[3], pVecBounds[1], // front
- pVecBounds[4], pVecBounds[5], pVecBounds[7], pVecBounds[6], // back
- pVecBounds[0], pVecBounds[4], pVecBounds[6], pVecBounds[2], // left
- pVecBounds[1], pVecBounds[3], pVecBounds[7], pVecBounds[5], // right
- pVecBounds[2], pVecBounds[6], pVecBounds[7], pVecBounds[3], // top
- pVecBounds[0], pVecBounds[4], pVecBounds[5], pVecBounds[1], // bottom
- };
- D3DXVECTOR3* pEdge;
- D3DXVECTOR3* pFace;
- pEdge = &edge[0][0];
- for( INT iEdge = 0; iEdge < 12; iEdge++ )
- {
- pFace = &face[0][0];
- for( INT iFace = 0; iFace < 6; iFace++ )
- {
- if( EdgeIntersectsFace( pEdge, pFace, &pPlaneBounds[iFace] ) )
- {
- return CS_INSIDE_SLOW;
- }
- pFace += 4;
- }
- pEdge += 2;
- }
-
- // Now see if any of the bounding box edges penetrate any of the faces of
- // the frustum
- D3DXVECTOR3 edge2[12][2] =
- {
- pVecBounds[0], pVecBounds[1], // front bottom
- pVecBounds[2], pVecBounds[3], // front top
- pVecBounds[0], pVecBounds[2], // front left
- pVecBounds[1], pVecBounds[3], // front right
- pVecBounds[4], pVecBounds[5], // back bottom
- pVecBounds[6], pVecBounds[7], // back top
- pVecBounds[4], pVecBounds[6], // back left
- pVecBounds[5], pVecBounds[7], // back right
- pVecBounds[0], pVecBounds[4], // left bottom
- pVecBounds[2], pVecBounds[6], // left top
- pVecBounds[1], pVecBounds[5], // right bottom
- pVecBounds[3], pVecBounds[7], // right top
- };
- D3DXVECTOR3 face2[6][4] =
- {
- pCullInfo->vecFrustum[0], pCullInfo->vecFrustum[2], pCullInfo->vecFrustum[3], pCullInfo->vecFrustum[1], // front
- pCullInfo->vecFrustum[4], pCullInfo->vecFrustum[5], pCullInfo->vecFrustum[7], pCullInfo->vecFrustum[6], // back
- pCullInfo->vecFrustum[0], pCullInfo->vecFrustum[4], pCullInfo->vecFrustum[6], pCullInfo->vecFrustum[2], // left
- pCullInfo->vecFrustum[1], pCullInfo->vecFrustum[3], pCullInfo->vecFrustum[7], pCullInfo->vecFrustum[5], // right
- pCullInfo->vecFrustum[2], pCullInfo->vecFrustum[6], pCullInfo->vecFrustum[7], pCullInfo->vecFrustum[3], // top
- pCullInfo->vecFrustum[0], pCullInfo->vecFrustum[4], pCullInfo->vecFrustum[5], pCullInfo->vecFrustum[1], // bottom
- };
- pEdge = &edge2[0][0];
- for( iEdge = 0; iEdge < 12; iEdge++ )
- {
- pFace = &face2[0][0];
- for( INT iFace = 0; iFace < 6; iFace++ )
- {
- if( EdgeIntersectsFace( pEdge, pFace, &pCullInfo->planeFrustum[iFace] ) )
- {
- return CS_INSIDE_SLOW;
- }
- pFace += 4;
- }
- pEdge += 2;
- }
-
- // Now see if frustum is contained in bounding box
- // If any frustum corner point is outside any plane of the bounding box,
- // the frustum is not contained in the bounding box, so the object
- // is outside the frustum
- for( INT iPlane = 0; iPlane < 6; iPlane++ )
- {
- if( pPlaneBounds[iPlane].a * pCullInfo->vecFrustum[0].x +
- pPlaneBounds[iPlane].b * pCullInfo->vecFrustum[0].y +
- pPlaneBounds[iPlane].c * pCullInfo->vecFrustum[0].z +
- pPlaneBounds[iPlane].d < 0 )
- {
- return CS_OUTSIDE_SLOW;
- }
- }
-
- // Bounding box must contain the frustum, so render the object
- return CS_INSIDE_SLOW;
- }
-
-
-
-
- //-----------------------------------------------------------------------------
- // Name: EdgeIntersectsFace()
- // Desc: Determine if the edge bounded by the two vectors in pEdges intersects
- // the quadrilateral described by the four vectors in pFacePoints.
- // Note: pPlane could be derived from pFacePoints using
- // D3DXPlaneFromPoints, but it is precomputed in advance for greater
- // speed.
- //-----------------------------------------------------------------------------
- BOOL EdgeIntersectsFace( D3DXVECTOR3* pEdges, D3DXVECTOR3* pFacePoints,
- D3DXPLANE* pPlane )
- {
- // If both edge points are on the same side of the plane, the edge does
- // not intersect the face
- FLOAT fDist1;
- FLOAT fDist2;
- fDist1 = pPlane->a * pEdges[0].x + pPlane->b * pEdges[0].y +
- pPlane->c * pEdges[0].z + pPlane->d;
- fDist2 = pPlane->a * pEdges[1].x + pPlane->b * pEdges[1].y +
- pPlane->c * pEdges[1].z + pPlane->d;
- if( fDist1 > 0 && fDist2 > 0 ||
- fDist1 < 0 && fDist2 < 0 )
- {
- return FALSE;
- }
-
- // Find point of intersection between edge and face plane (if they're
- // parallel, edge does not intersect face and D3DXPlaneIntersectLine
- // returns NULL)
- D3DXVECTOR3 ptIntersection;
- if( NULL == D3DXPlaneIntersectLine( &ptIntersection, pPlane, &pEdges[0], &pEdges[1] ) )
- return FALSE;
-
- // Project onto a 2D plane to make the pt-in-poly test easier
- FLOAT fAbsA = (pPlane->a > 0 ? pPlane->a : -pPlane->a);
- FLOAT fAbsB = (pPlane->b > 0 ? pPlane->b : -pPlane->b);
- FLOAT fAbsC = (pPlane->c > 0 ? pPlane->c : -pPlane->c);
- D3DXVECTOR2 facePoints[4];
- D3DXVECTOR2 point;
- if( fAbsA > fAbsB && fAbsA > fAbsC )
- {
- // Plane is mainly pointing along X axis, so use Y and Z
- for( INT i = 0; i < 4; i++)
- {
- facePoints[i].x = pFacePoints[i].y;
- facePoints[i].y = pFacePoints[i].z;
- }
- point.x = ptIntersection.y;
- point.y = ptIntersection.z;
- }
- else if( fAbsB > fAbsA && fAbsB > fAbsC )
- {
- // Plane is mainly pointing along Y axis, so use X and Z
- for( INT i = 0; i < 4; i++)
- {
- facePoints[i].x = pFacePoints[i].x;
- facePoints[i].y = pFacePoints[i].z;
- }
- point.x = ptIntersection.x;
- point.y = ptIntersection.z;
- }
- else
- {
- // Plane is mainly pointing along Z axis, so use X and Y
- for( INT i = 0; i < 4; i++)
- {
- facePoints[i].x = pFacePoints[i].x;
- facePoints[i].y = pFacePoints[i].y;
- }
- point.x = ptIntersection.x;
- point.y = ptIntersection.y;
- }
-
- // If point is on the outside of any of the face edges, it is
- // outside the face.
- // We can do this by taking the determinant of the following matrix:
- // | x0 y0 1 |
- // | x1 y1 1 |
- // | x2 y2 1 |
- // where (x0,y0) and (x1,y1) are points on the face edge and (x2,y2)
- // is our test point. If this value is positive, the test point is
- // "to the left" of the line. To determine whether a point needs to
- // be "to the right" or "to the left" of the four lines to qualify as
- // inside the face, we need to see if the faces are specified in
- // clockwise or counter-clockwise order (it could be either, since the
- // edge could be penetrating from either side). To determine this, we
- // do the same test to see if the third point is "to the right" or
- // "to the left" of the line formed by the first two points.
- // See http://forum.swarthmore.edu/dr.math/problems/scott5.31.96.html
- FLOAT x0, x1, x2, y0, y1, y2;
- x0 = facePoints[0].x;
- y0 = facePoints[0].y;
- x1 = facePoints[1].x;
- y1 = facePoints[1].y;
- x2 = facePoints[2].x;
- y2 = facePoints[2].y;
- BOOL bClockwise = FALSE;
- if( x1*y2 - y1*x2 - x0*y2 + y0*x2 + x0*y1 - y0*x1 < 0 )
- bClockwise = TRUE;
- x2 = point.x;
- y2 = point.y;
- for( INT i = 0; i < 4; i++ )
- {
- x0 = facePoints[i].x;
- y0 = facePoints[i].y;
- if( i < 3 )
- {
- x1 = facePoints[i+1].x;
- y1 = facePoints[i+1].y;
- }
- else
- {
- x1 = facePoints[0].x;
- y1 = facePoints[0].y;
- }
- if( ( x1*y2 - y1*x2 - x0*y2 + y0*x2 + x0*y1 - y0*x1 > 0 ) == bClockwise )
- return FALSE;
- }
-
- // If we get here, the point is inside all four face edges,
- // so it's inside the face.
- return TRUE;
- }
-